package com.lovemanai.tools.jdbc;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;


/**
 * jdbc小工具
 * 特性：底层使用c3p0连接池，可以获得Connection对象和DataSource对象，支持事务，使用ThreadLocal类支持多线程并发访问
 * 方法说明：
 * public static Connection getConnection() throws SQLException;//获得一个Connection对象
 * public static DataSource getDataSource();//获得一个DataSource对象
 * public static void beginTransaction() throws SQLException;//开启事务
 * public static void commitTransaction() throws SQLException;//提交事务
 * public static void rollbackTransaction() throws SQLException;//回滚事务
 * 
 * @version 1.2
 * @author lovemanai
 *
 */
public class JdbcUtils {
	
	private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
	
	//使用ThreadLocal类解决多线程访问的问题
	private static ThreadLocal<Connection> tlConn = new ThreadLocal<Connection>();
	//private static Connection conn = null;//将一个Connection对象作为属性，那么在下面的方法都会使用同一个Connection
	
	/**
	 * 获得一个Connection
	 * @return
	 * @throws SQLException
	 */
	public static Connection getConnection() throws SQLException {
		/*
		 * 1.获得当前线程的连接，如果不为空，说明已经开启事务，则不需要重复获得连接
		 * 2.获得连接返回
		 */
		
		Connection conn = tlConn.get();//获得当前连接的Connection
		//如果conn不为空，直接返回
		if(conn != null) return conn;
		//获得连接
		conn = dataSource.getConnection(); 
		return conn;
	}
	
	/**
	 * 获得DataSource对象
	 * @return
	 */
	public static DataSource getDataSource() {
		return dataSource;
	}
	
	/**
	 * 开启事务
	 * @throws SQLException
	 */
	public static void beginTransaction() throws SQLException {
		/*
		 * 1.获取当前线程的连接
		 * 2.如果连接不为空，说明已经开始了事务，不能重复开启
		 * 3.获得连接
		 * 4.设置手动提交
		 * 5.保存当前连接，以便于后面都可以使用
		 */
		Connection conn = tlConn.get();
		if(conn != null) throw new SQLException("已经开启事务，不要重复开启事务");
		conn = getConnection();//获得连接
		conn.setAutoCommit(false);//设置为手动提交，开启事务
		tlConn.set(conn);//保存当前线程的连接	
	}
	
	/**
	 * 提交事务
	 * @throws SQLException
	 */
	public static void commitTransaction() throws SQLException {
		/*
		 * 1.获取当前线程的连接
		 * 2.如果连接为空，说明没有开启事务，不能提交事务
		 * 3.提交事务
		 * 4.处理完事务，关闭连接，将连接从当前线程移除 
		 */
		Connection conn = tlConn.get();
		if(conn == null) throw new SQLException("没有开启事务，不能提交");
		conn.commit();//提交事务
		conn.close();//处理完事务关闭连接
		tlConn.remove();//移除连接
	}
	
	/**
	 * 回滚事务
	 * @throws SQLException
	 */
	public static void rollbackTransaction() throws SQLException {
		/*
		 * 1.获得当前线程的连接
		 * 2.如果连接为空，说明没有开启事务，不能回滚事务
		 * 3.回滚事务
		 * 4.回滚结束，关闭连接，将连接从当前线程移除
		 */
		Connection conn = tlConn.get();
		if(conn == null) throw new SQLException("没有开启事务，不能回滚");
		conn.rollback();//事务回滚
		conn.close();//关闭连接
		tlConn.remove();//移除连接
	}
	
	public static void realeaseConnection(Connection connection) throws SQLException {
		//获取当前线程的连接
		Connection conn = tlConn.get();
		//如果当前线程连接为空，说明当前连接一定不是事务专用，可以关闭之。
		if(conn == null) connection.close();
		//如果当前线程连接和需要关闭的连接不是同一连接，可以关闭之
		if(conn != connection) connection.close();
		
	}
} 
